package com.zebra.gateway.processor;

import com.zebra.common.OfflineType;
import com.zebra.common.OnlineType;
import com.zebra.common.ZbmAreaType;
import com.zebra.common.ZbmMessage;
import com.zebra.gateway.GwConfigInfoManager;
import com.zebra.gateway.protocol.GatewayCommand;
import com.zebra.gateway.session.Session;
import com.zebra.gateway.session.SessionManager;
import com.zebra.remoting.NotifyProxy;
import com.zebra.remoting.config.BasisCommandCode;
import com.zebra.remoting.config.GwRegisterMessage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.util.Arrays;
import java.util.List;

public class ServerBasisHandlerProcessor extends AbstractGatewayProcessor {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBasisHandlerProcessor.class);

    @Override
    public void doProcess(ChannelHandlerContext ctx, GatewayCommand msg) throws  Exception {

        BasisCommandCode commandCode = (BasisCommandCode) BasisCommandCode.valueOfCode(msg.getCmd());
        switch (commandCode){
            case        ASKTMS:   { doASKTMS(ctx, msg); break;}
            case REPEAT_LOGIN:   { doREPEAT_LOGIN(ctx, msg); break;}  //挤号
            case           ZBM:    { doZBM(ctx, msg); break;}        // 广播等
            case      RATOTMS:   { doRATOTMS(msg); break;}
            case        GWRTMS:   { doGWRTMS(ctx, msg); break;}
            default: {
                doDefault(ctx, msg);
            }
        }
    }

    private void doRATOTMS(GatewayCommand msg) throws Exception {
        GwRegisterMessage gwRegisterMessage = new GwRegisterMessage().read(msg.getMsgBuf());
        logger.info("Handler RATOTMS msg {}", gwRegisterMessage.toString());
        GatewayProcessorUtil.tmsStart(gwRegisterMessage);
    }

    private void doASKTMS(ChannelHandlerContext ctx, GatewayCommand msg){
        NotifyProxy.notifyProxy.ackSyncMsg(ctx.channel(), msg);
    }

    private void doGWRTMS(ChannelHandlerContext ctx, GatewayCommand msg){
        NotifyProxy.notifyProxy.ackSyncMsg(ctx.channel(), msg);
    }

    private void doREPEAT_LOGIN(ChannelHandlerContext ctx, GatewayCommand msg){
        Session session = SessionManager.getInstance().getSession(msg.getUserId());
        logger.info("Handler REPEAT_LOGIN command {} {}", null == session ? "session is null" : session.toString(),  msg);
        if (null == session){
            msg.release();
            return;
        }

        if (!session.isWeakClose() && session.channelFine()){
            session.getChannel().writeAndFlush(msg);
        }else {
            msg.release();
        }
        GatewayProcessorUtil.sendTmsInactiveChannel(session, OfflineType.Repeat);
        SessionManager.getInstance().removeBySession(session);
    }

    private void doZBM(ChannelHandlerContext ctx, GatewayCommand msg){
        ZbmMessage zbmMessage = new ZbmMessage().read(msg.getMsgBuf());
        logger.info("Handler ZBM {} {}", msg.toString(), zbmMessage.toString());
        ZbmAreaType areaType = ZbmAreaType.codeOf(zbmMessage.getZbmArea());
        List<Session> sessionList = null;
        switch (areaType){
            case Global: sessionList = SessionManager.getInstance().getAllFine(); break;
            case Game:   sessionList = SessionManager.getInstance().getGames(zbmMessage.getGameIds()); break;
            case Person: sessionList = SessionManager.getInstance().getPerson(zbmMessage.getUserIds()); break;
        }
        if (null == sessionList || sessionList.isEmpty()){
            logger.error("Handler ZBM  Session list is null {}", zbmMessage.toString());
            return;
        }

        long[] userIds = sessionList.stream().mapToLong(Session::getUserId).toArray();
        logger.info("Handler ZBM Send sessionIds: {}", Arrays.toString(userIds));
        sessionList.forEach(s -> {
            ByteBuf byteBuf = PooledByteBufAllocator.DEFAULT.directBuffer();
            zbmMessage.writeByPlayer(byteBuf);

            GatewayCommand command = GatewayCommand.builder()
                    .cmd(msg.getCmd())
                    .msgBuf(byteBuf)
                    .state(200)
                    .build();
            command.byteBufEncoder();
            s.getChannel().writeAndFlush(command);

        });

    }

    private void doDefault(ChannelHandlerContext ctx, GatewayCommand msg)throws  Exception{
        logger.info("Handler doDefault: {}", msg.toString());
        GwConfigInfoManager.getInstance().getGwServerInfo().setOnline(OnlineType.OffLine.value());
        GatewayProcessorUtil.sendOfflineStatus();
    }

}
